#include <stdio.h>
#include <stdlib.h>
#include "bit.h"

#define MINBUFLEN	4096

//-----------------------------------------------------------------------------
void bit_put0(bitbuf_t * dst)
//-----------------------------------------------------------------------------
{
	*dst->curs &= ~(dst->bit);
	dst->bit <<= 1;
	//ça ne marche uniquement pck dst->bit est contraint sur 8 bits !!!
	if( ! dst->bit ) { dst->curs++; dst->bit=0x00000001;}
}

//-----------------------------------------------------------------------------
void bit_put1(bitbuf_t * dst)
//-----------------------------------------------------------------------------
{
	*dst->curs |= dst->bit;
	dst->bit <<= 1;
	if( ! dst->bit ) { dst->curs++; dst->bit=0x00000001;}
}

//-----------------------------------------------------------------------------
int  bit_get(bitbuf_t * src)
//-----------------------------------------------------------------------------
{
	int res;

	res = (*src->curs) & src->bit;
	src->bit <<= 1;
	if(! src->bit) { src->curs++; src->bit=0x01;}

	return res;
}

//-----------------------------------------------------------------------------
void   bit_write(bitbuf_t* dst, bloc_t b, bitcount_t bc)
//-----------------------------------------------------------------------------
{
	unsigned int lshift=0,rshift=8,cpt=0;

	while( (dst->bit)>>lshift > 0x01 ){lshift++;} //calcul du #bits à supprimer au début (7 tests max 4 en moy)
	//printf("bit = 0x%04X\n",dst->bit);
	//printf("lshift = %d \n", lshift);
	//if(bc>32) printf("NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOON !");

	*dst->curs &= dst->bit - 1; //force à zéro les bits non utilisés avant écriture
	*dst->curs |= (b<<lshift);

	rshift -= lshift;
	cpt=bc+lshift;
	while(cpt>8)
	{
		dst->curs++;
		*dst->curs = b>>rshift;
		cpt-=8;
		rshift+=8;
	}
	//if(cpt==8) dst->curs++;
	dst->bit = 0x01<<cpt;
	if(! dst->bit ){ dst->curs++; dst->bit=0x01; }
}

//-----------------------------------------------------------------------------
bloc_t bit_read(bitbuf_t * src, bitcount_t bc)
//-----------------------------------------------------------------------------
{
	bloc_t b=0x00000000;
	unsigned int rshift=0;

	while( (src->bit)>>rshift > 0x01 ){rshift++;}

	//copier 32 bits (sans se soucier de l'endianess)
	b |= src->curs[0] & 0x000000FF;
	b |= (src->curs[1]<<8) & 0x0000FFFF;
	b |= (src->curs[2]<<16) & 0x00FFFFFF;
	b |= src->curs[3]<<24;
	//printf("0x%08X\n",b);
	b >>= rshift;
	//printf("0x%08X\n",b);
	if(bc+rshift > 32)	b |= src->curs[4]<<(32-rshift);
	//printf("0x%08X\n",b);

	//supression de bits en trop de
	b &= (0x01<<bc)-1;
	//printf("0x%08X\n",b);

	src->curs += (bc+rshift)/8;
	src->bit  = 0x01<<((bc+rshift)%8);

	return b;
}


//-----------------------------------------------------------------------------
void bit_initBuf(bitbuf_t * buf, size_t len)
//-----------------------------------------------------------------------------
{
	size_t lenByte = ((len-1)/8)+1+5; // +4 pour avoir un peu de marge
	if(len){buf->data=(byte *)malloc(lenByte); buf->len = len;}
	else{   buf->data=(byte *)malloc(MINBUFLEN); buf->len = MINBUFLEN*8;}
	buf->curs	= buf->data;
	buf->bit	= 0x01;
}

//-----------------------------------------------------------------------------
void bit_freeBuf(bitbuf_t * buf)
//-----------------------------------------------------------------------------
{
	free(buf->data);
	buf->len =0;
	buf->data = NULL;
	buf->curs = NULL;
}

//-----------------------------------------------------------------------------
void bit_printbloc(bloc_t b)
//-----------------------------------------------------------------------------
{
	int i=0;
	bloc_t mask=0x01;

	printf(" (");
	for(;i<32; i++)
	{
		(b & (mask<<i)) ? printf("1") : printf("0");
	}
	printf(") ");
}

//-----------------------------------------------------------------------------
void bit_print(bitbuf_t * buf)
//-----------------------------------------------------------------------------
{
	int i=0;
	bitbuf_t b = *buf;

	b.curs =b.data; b.bit=0x01;
	printf("||");

	for(;i<b.len; i++)
	{
		if(i%8 == 0) printf(" ");
		bit_get(&b) ? printf("1") : printf("0");
	}
	printf(" ||\n");
}

//-----------------------------------------------------------------------------
size_t bit_getpos(bitbuf_t * buf)
//-----------------------------------------------------------------------------
{
	unsigned int i=0;
	while( (buf->bit)>>i > 0x01 ){i++;}

	return 8*(buf->curs -buf->data) + i;
}

//-----------------------------------------------------------------------------
size_t bit_seek(bitbuf_t * buf, size_t byteOffset, bitcount_t bitOffset, int whence)
//-----------------------------------------------------------------------------
{
	bitcount_t i=0;
	size_t pos=0;

	while( (buf->bit)>>i > 0x01 ){i++;}

	switch(whence){
	case BITSEEK_SET:
		buf->curs = buf->data + byteOffset;
		if(i+bitOffset > 7 ) buf->curs += (i+bitOffset)/8;
		buf->bit  = 0x01<<bitOffset%8;
		break;
	default: //BITSEEK_CUR
		buf->curs +=  byteOffset + (i+bitOffset)/8;
		if(i+bitOffset > 7 ) buf->curs += (i+bitOffset)/8;
		buf->bit  = 0x01<<((i+bitOffset)%8);
		break;
	}

	while( (buf->bit)>>i > 0x01 ){i++;}

	pos = 8*(buf->curs - buf->data) + i;

	return pos;
}

//
